package edu.se.jai.websocketgateway.config;

import edu.se.jai.dubboapi.proto.GameServiceProto.*;
import edu.se.jai.dubboapi.service.GameServiceApi;
import edu.se.jai.websocketgateway.service.MessageSendService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.context.event.EventListener;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.messaging.SessionDisconnectEvent;

/**
 * WebSocket事件监听器（Dubbo版）
 *
 * 职责：
 * - 监听 WebSocket 断开事件，协调 Redis 与房间状态的清理
 * - 通过 Dubbo3 调用 `game-service` 完成房间解散或离开逻辑
 * - 保证房主断线时房间被解散，普通玩家断线时自动离开房间
 * - 始终通知网关向前端广播最新的房间状态
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class WebSocketEventListener {

    @DubboReference(interfaceClass = GameServiceApi.class, protocol = "tri", check = false)
    private GameServiceApi gameServiceClient;
    
    private final MessageSendService messageSendService;

    /**
     * 处理客户端断线事件，按照“查询房间 → 解散/离开 → 清理玩家信息”三步执行。
     */
    @EventListener
    public void handleWebSocketDisconnectListener(SessionDisconnectEvent event) {
        StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(event.getMessage());
        String sessionId = headerAccessor.getSessionId();

        log.info("WebSocket连接断开 - Session ID: {}", sessionId);

        try {
            SessionRequest sessionRequest = SessionRequest.newBuilder()
                    .setSessionId(sessionId)
                    .build();

            Result roomProtoResult = gameServiceClient.getRoomBySessionId(sessionRequest);
            
            if (!roomProtoResult.getSuccess()) {
                log.info("断线玩家不在任何房间中 - Session ID: {}", sessionId);
                clearPlayerInfo(sessionId);
                return;
            }
            
            GameRoomDto room = roomProtoResult.getGameRoomDto();
            String roomId = room.getRoomId();
            int originalPlayerCount = room.getPlayersCount();
            
            SessionRoomRequest sessionRoomRequest = SessionRoomRequest.newBuilder()
                    .setSessionId(sessionId)
                    .setRoomId(roomId)
                    .build();

            Result dissolveProtoResult = gameServiceClient.dissolveRoom(sessionRoomRequest);
            
            if (dissolveProtoResult.getSuccess()) {
                log.info("房间创建者断线，解散房间: sessionId={}, roomId={}, 原房间人数: {}", 
                        sessionId, roomId, originalPlayerCount);
                messageSendService.notifyRoomDissolved(dissolveProtoResult.getGameRoomDto());
                log.info("已清理断线创建者房间数据 - Session ID: {}", sessionId);
            } else {
                Result leaveProtoResult = gameServiceClient.leaveRoom(sessionRoomRequest);
                
                if (leaveProtoResult.getSuccess()) {
                    log.info("玩家断线，离开房间: sessionId={}, roomId={}, 原房间人数: {}", 
                            sessionId, roomId, originalPlayerCount);
                    GameRoomDto updatedRoom = leaveProtoResult.getGameRoomDto();
                    messageSendService.notifyLeave(updatedRoom, sessionId);
                    log.info("已清理断线玩家房间数据 - Session ID: {}", sessionId);
                } else {
                    log.warn("玩家离开房间失败: sessionId={}, roomId={}, 错误: {}", 
                            sessionId, roomId, leaveProtoResult.getErrorMessage());
                }
            }
            
            clearPlayerInfo(sessionId);
            
        } catch (Exception e) {
            log.error("处理玩家断线事件时发生异常 - Session ID: {}, 异常: {}", sessionId, e.getMessage(), e);
            clearPlayerInfo(sessionId);
        }
    }
    
    private void clearPlayerInfo(String sessionId) {
        try {
            SessionRequest request = SessionRequest.newBuilder()
                    .setSessionId(sessionId)
                    .build();

            Result clearProtoResult = gameServiceClient.clearPlayer(request);
            if (clearProtoResult.getSuccess()) {
                log.info("已清除玩家基本信息 - Session ID: {}", sessionId);
            } else {
                log.warn("清除玩家基本信息失败: sessionId={}, 错误: {}", 
                        sessionId, clearProtoResult.getErrorMessage());
            }
        } catch (Exception e) {
            log.error("清除玩家基本信息时发生异常: sessionId={}, 异常: {}", 
                    sessionId, e.getMessage(), e);
        }
    }
}

